////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "BoundingVolumes.h"

#include <SFML/OpenGL.hpp>

#include "../Math.hpp"

#ifdef _DEBUG
#include <SFML/Graphics.hpp>
#endif

#include <SmegTools/Debug/DebugNew.hpp>

namespace smeg {
    namespace math {
        
////////////////////////////////////////////////////////////
/// Default Constructor
////////////////////////////////////////////////////////////
Circle::Circle( const sf::Vector2f& _Center, float _fRadius ) :
    BoundingVolume( eCircle, _Center, sf::Vector2f( _fRadius, _fRadius ) )
{
}
        
////////////////////////////////////////////////////////////
/// Default Constructor
////////////////////////////////////////////////////////////
Circle::Circle( const Circle& _Copy ) :
    BoundingVolume( _Copy )
{
}
    
////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
Circle::~Circle()
{
}

////////////////////////////////////////////////////////////
/// Does the Bounding Volume overlaps with another volume
////////////////////////////////////////////////////////////
bool Circle::Overlaps( const BoundingBox& _Other ) const {
    return BoundingVolume::Overlaps( _Other, *this );
}

bool Circle::Overlaps( const Circle& _Other ) const {
    float r = m_HalfSize.x + _Other.m_HalfSize.x;

    return r * r > SquaredLength( m_Center - _Other.m_Center );
}

bool Circle::Overlaps( const Line& _Other ) const {
    return BoundingVolume::Overlaps( *this, _Other );
}

////////////////////////////////////////////////////////////
/// Does the Bounding Volume contains another volume
////////////////////////////////////////////////////////////
bool Circle::Contains( const BoundingBox& _Other ) const {
    // TODO See if there isn't a better/faster way
    if ( _Other.IsAxisAligned() ) {
        float fRadiusSquared = m_HalfSize.x * m_HalfSize.x;
        const sf::Vector2f& lowerBound( _Other.GetLowerBound() ),
            & upperBound( _Other.GetUpperBound() );
        sf::Vector2f lowerUpperBound( lowerBound.x, upperBound.y ),
            upperLowerBound( upperBound.x, lowerBound.y );

        return SquaredLength( m_Center - lowerBound ) <= fRadiusSquared &&
            SquaredLength( m_Center - upperBound ) <= fRadiusSquared &&
            SquaredLength( m_Center - lowerUpperBound ) <= fRadiusSquared &&
            SquaredLength( m_Center - upperLowerBound ) <= fRadiusSquared;
    } else {
        const sf::Vector2f* pCorners = _Other.GetCorners();
        return Contains( pCorners[BoundingBox::eTopLeft] ) &&
            Contains( pCorners[BoundingBox::eTopRight] ) &&
            Contains( pCorners[BoundingBox::eBottomLeft] ) &&
            Contains( pCorners[BoundingBox::eBottomRight] );
    }
}

bool Circle::Contains( const Circle& _Other ) const {
    return Length( m_Center - _Other.m_Center ) + _Other.m_HalfSize.x <= m_HalfSize.x;
}

bool Circle::Contains( const Line& _Other ) const {
    const sf::Vector2f* _pLineExtents = _Other.GetExtents();

    return Contains( _pLineExtents[0] ) && Contains( _pLineExtents[1] );
}

////////////////////////////////////////////////////////////
/// Does the Bounding Volume contains a point
////////////////////////////////////////////////////////////
bool Circle::Contains( const sf::Vector2f& _Point ) const {
    return SquaredLength( m_Center - _Point ) <= m_HalfSize.x * m_HalfSize.x;
}

#ifdef _DEBUG
void Circle::DebugRender( sf::RenderWindow* _pRenderWindow, const sf::Color& _Color, bool _bFull ) const {
    sf::CircleShape Circle( m_HalfSize.x );
    Circle.setOrigin( m_HalfSize );
    Circle.setPosition( m_Center );

    if ( _bFull ) {
        Circle.setFillColor( _Color );
    } else {
        Circle.setFillColor( sf::Color::Transparent );
        Circle.setOutlineColor( _Color );
        Circle.setOutlineThickness( 1.0f );
    }

    _pRenderWindow->draw( Circle );
}
#endif // _DEBUG
    } // smeg::math
} // smeg